package com.bj58.mis.apm.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;


/**
 * 〈一句话功能简述〉<br>
 * 〈请求信息拦截器〉
 *
 * @author zhangyu84
 * @create 2018/6/6
 * @since 1.0.0
 */
public class RequestInfoInterceptor implements HandlerInterceptor {
    private static Logger logger = LoggerFactory.getLogger(RequestInfoInterceptor.class);
    private NamedThreadLocal<Long> startTimeThreadLocal =
            new NamedThreadLocal<>("StopWatch-StartTime");
    private NamedThreadLocal<String> requestInfo =
            new NamedThreadLocal<>("StopWatch-requestInfo");

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        startTimeThreadLocal.set(startTime);
        if (handler instanceof HandlerMethod) {
            StringBuilder sb = new StringBuilder();
            sb.append("\n-----------------------").append(LocalDateTime.now())
                    .append("----------------------------\n");
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            sb.append("RequestIP:").append(getIpAddress(request));
            sb.append("Controller:").append(handlerMethod.getBean().getClass().getName()).append("\n");
            sb.append("Method:").append(handlerMethod.getMethod().getName()).append("\n");
            sb.append("Params:").append(getParamString(request.getParameterMap())).append("\n");
            sb.append("URI:").append(request.getRequestURI()).append("\n");
            requestInfo.set(sb.toString());
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        long startTime = startTimeThreadLocal.get();
        long endTime = System.currentTimeMillis();
        if (handler instanceof HandlerMethod) {
            StringBuilder stringBuilder = new StringBuilder(requestInfo.get());
            stringBuilder.append("ExecuteTime:").append(endTime - startTime).append("ms").append("\n");
            stringBuilder.append("StatusCode:").append(response.getStatus()).append("\n");
            stringBuilder.append("-------------------------------------------------------------------------------");
            logger.info(stringBuilder.toString());
        }
    }


    private String getParamString(Map<String, String[]> map) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, String[]> e : map.entrySet()) {
            stringBuilder.append(e.getKey()).append("=");
            String[] val = e.getValue();
            if (val != null && val.length == 1) {
                stringBuilder.append(val[0]).append("\t");
            } else {
                stringBuilder.append(Arrays.toString(val)).append("\t");
            }
        }
        return stringBuilder.toString();
    }

    private String getIpAddress(HttpServletRequest request) {

        String xIp = request.getHeader("X-Real-IP");
        String xFor = request.getHeader("X-Forwarded-For");
        String REQUEST_FOR_STRING="unKnown";
        if(StringUtils.isNotEmpty(xFor) && !REQUEST_FOR_STRING.equalsIgnoreCase(xFor)){
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = xFor.indexOf(",");
            if(index != -1){
                return xFor.substring(0,index);
            }else{
                return xFor;
            }
        }
        xFor = xIp;
        if(StringUtils.isNotEmpty(xFor) && !REQUEST_FOR_STRING.equalsIgnoreCase(xFor)){
            return xFor;
        }
        if (StringUtils.isBlank(xFor) || REQUEST_FOR_STRING.equalsIgnoreCase(xFor)) {
            xFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(xFor) || REQUEST_FOR_STRING.equalsIgnoreCase(xFor)) {
            xFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(xFor) || REQUEST_FOR_STRING.equalsIgnoreCase(xFor)) {
            xFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(xFor) || REQUEST_FOR_STRING.equalsIgnoreCase(xFor)) {
            xFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(xFor) || REQUEST_FOR_STRING.equalsIgnoreCase(xFor)) {
            xFor = request.getRemoteAddr();
        }
        return xFor;
    }
}
